#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <thread>
#include <chrono>
#include "json.hpp"
#include "tinyformat/tinyformat.h" // 引入 Tinyformat 头文件
#include "termcolor/termcolor.hpp" // termcolor 控制台颜色库

using json = nlohmann::json;
using namespace std;

// 游戏状态
struct GameState {
    string currentNode; // 当前节点
    json data; // 游戏数据
    string playerName; // 玩家名称
    unordered_map<string, string> characterDescriptions; // 角色描述
};

// 清屏
void clearScreen() {
#ifdef _WIN32
    system("cls");
#else
    system("clear");
#endif
}

// 延迟逐字输出并通过Enter控制继续
void typewriterEffect(string text, int delay = 30) {
    // 替换自定义换行标记为实际换行符
    size_t pos = 0;
    while ((pos = text.find("#%#", pos)) != string::npos) {
        text.replace(pos, 3, "\n"); // 替换“#%#”为换行符
        pos += 1; // 移动位置以避免无限循环
    }

    for (char c : text) {
        cout << c;
        cout.flush();
        this_thread::sleep_for(chrono::milliseconds(delay));
    }
    cout << endl;

    // 按下Enter键继续
    cout << termcolor::magenta << "\n=== 按Enter键继续游戏 ===\n" << termcolor::reset;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
}

// 显示剧情文本和选择项
void displayText(const GameState& state) {
    const json& current = state.data[state.currentNode];

    cout << termcolor::yellow;
    tinyformat::printf("\n========== 游戏进行中 ==========\n");
    cout << termcolor::reset;

    // 角色说话
    string speaker = current.contains("speaker") ? current["speaker"].get<string>() : "旁白";
    
    // 检查角色是否是定义的角色
    if (speaker == "player") {
        // 如果说话者是玩家自己
        speaker = state.playerName; // 使用玩家的名字
    }

    if (state.characterDescriptions.find(speaker) != state.characterDescriptions.end()) {
        // 如果角色在角色描述中定义，显示角色描述
        cout << termcolor::cyan << speaker << "：" << termcolor::reset;
    } else {
        // 如果角色未定义，直接显示角色名字
        cout << termcolor::cyan << speaker << "：" << termcolor::reset;
    }

    // 使用逐字输出效果显示文本
    typewriterEffect(current["text"]);

    if (current["choices"].empty()) {
        return;
    }

    cout << "\n请选择一个选项:\n";
    int index = 1;
    for (const auto& choice : current["choices"].items()) {
        cout << termcolor::green;
        tinyformat::printf("  [%d] %s\n", index++, choice.key().c_str());
        cout << termcolor::reset;
    }

    cout << termcolor::yellow;
    tinyformat::printf("================================\n");
    cout << termcolor::reset;
}

// 处理用户输入
void handleInput(GameState& state) {
    int choice;
    string input;
    
    while (true) {
        cout << termcolor::cyan << "请输入选项编号 (或输入 'q' 退出游戏): " << termcolor::reset;
        cin >> input;

        if (input == "q") {
            cout << termcolor::red << "您已退出游戏。\n" << termcolor::reset;
            exit(0);  // 退出游戏
        }

        try {
            choice = stoi(input);
        } catch (exception& e) {
            cout << termcolor::red << "无效输入，请输入数字或 'q' 退出。\n" << termcolor::reset;
            continue;
        }

        const json& current = state.data[state.currentNode];
        auto choices = current["choices"];
        if (choice >= 1 && choice <= choices.size()) {
            string selectedChoice;
            int i = 1;
            for (const auto& item : choices.items()) {
                if (i++ == choice) {
                    selectedChoice = item.key();
                    break;
                }
            }
            string nextNode = choices[selectedChoice];
            if (nextNode.empty()) {
                nextNode = state.currentNode; // 如果选择项为空，保持在当前节点
            }
            state.currentNode = nextNode;
            break;
        } else {
            cout << termcolor::red << "无效选择，请重新输入，不然我不知道你的意思哦，喵~\n" << termcolor::reset;
        }
    }
}

// 加载数据
void loadData(GameState& state) {
    ifstream file("data.json");
    if (file.is_open()) {
        file >> state.data;
        state.currentNode = "intro"; // 从开场白节点开始

        // 读取玩家名称
        state.playerName = state.data["player"]["name"].get<string>();

        // 读取角色信息
        for (const auto& item : state.data["characters"].items()) {
            state.characterDescriptions[item.key()] = item.value()["description"];
        }
    } else {
        cerr << termcolor::red << "无法打开数据文件!!!" << termcolor::reset << endl;
        exit(1);
    }
}

// 加载进度
bool loadProgress(GameState& state) {
    ifstream progressFile("rop.json");
    if (progressFile.is_open()) {
        json progressData;
        progressFile >> progressData;
        state.currentNode = progressData["currentNode"].get<string>();
        return true;
    }
    return false;
}

// 保存进度
void saveProgress(const GameState& state) {
    ofstream progressFile("rop.json");
    if (progressFile.is_open()) {
        json progressData;
        progressData["currentNode"] = state.currentNode;
        progressFile << progressData.dump(4); // 格式化 JSON 文件
    }
}

// 主函数
int main() {
    GameState state;
    loadData(state);

    clearScreen(); // 游戏开始时清屏

    // 检查是否存在进度文件
    if (loadProgress(state)) {
        string response;
        cout << termcolor::yellow << "检测到保存的进度。是否从保存的进度继续游戏？(y/n): " << termcolor::reset;
        cin >> response;
        if (response != "y" && response != "Y") {
            state.currentNode = "intro"; // 选择从头开始游戏
            cout << termcolor::green << "从新游戏开始。" << termcolor::reset << endl;
        } else {
            cout << termcolor::green << "继续从保存的进度开始。" << termcolor::reset << endl;
        }
    } else {
        state.currentNode = "intro"; // 无进度文件，开始新游戏
        cout << termcolor::green << "开始新游戏。" << termcolor::reset << endl;
    }

    // 显示开场白
    const json& intro = state.data["intro"];
    cout << termcolor::yellow;
    typewriterEffect(intro["text"]); // 使用逐字输出显示开场白
    cout << termcolor::reset;

    while (true) {
        clearScreen(); // 每次显示新的剧情时清屏
        displayText(state);

        const json& current = state.data[state.currentNode];
        if (current["choices"].empty()) {
            cout << termcolor::red;
            tinyformat::printf("游戏结束，感谢游玩，游戏结束了，喵~\n");
            cout << termcolor::reset;
            saveProgress(state); // 保存进度
            break; // 如果没有更多选择，结束游戏
        }

        handleInput(state);
        saveProgress(state); // 保存进度
    }

    return 0;
}
